/*
 * @Description: js-sdk for cess storage
 * @Autor: cess lab
 */
import { web3Accounts, web3Enable, web3FromAddress, web3FromSource } from '@polkadot/extension-dapp';
import { stringToHex, hexToU8a} from "@polkadot/util";


export default class ControlBase {
  constructor(api, keyring, isDebug = false) {
    this.api = api;
    this.keyring = keyring;
    this.debug = isDebug;
  }

  log = (...msg) => {
    if (this.debug) {
      console.log(...msg);
    }
  };

  error = (...msg) => {
    if (this.debug) {
      console.error(...msg);
    }
  };

  // async sign(mnemonic, tx) {
  //   const api = this.api;
  //   const pair = this.keyring.createFromUri(mnemonic);
  //   const { nonce } = await api.query.system.account(pair.address);
  //   // create the payload
  //   const signer = api.createType("SignerPayload", {
  //     method: tx,
  //     nonce, 
  //     genesisHash: api.genesisHash,
  //     blockHash: api.genesisHash,
  //     runtimeVersion: api.runtimeVersion,
  //     version: api.extrinsicVersion,
  //   });
  //   const { signature } = api
  //     .createType("ExtrinsicPayload", signer.toPayload(), {
  //       version: api.extrinsicVersion,
  //     })
  //     .sign(pair);
  //   tx.addSignature(pair.address, signature, signer.toPayload());
  //   return tx.toHex();
  // }

  async submitTransaction(transaction) {
    /* eslint-disable-next-line no-async-promise-executor */
    return new Promise(async (resolve, reject) => {
      const api = this.api;
      let tx;
      try {
        tx = api.tx(transaction);
      } catch (err) {
        reject(err);
      }
      try {
        const hash = await api.rpc.author.submitExtrinsic(tx);
        resolve(hash.toHex());
      } catch (err) {
        reject(err);
      }
    });
  }

  async signAndSend(accountId32, extrinsic, subStateFun = null) {
    return new Promise(async (resolve, reject) => {
      try {
        const extensions = await web3Enable("CESS dApp");
        if (extensions.length === 0) {
          return reject("no extension installed, or the user did not accept the authorization");
        }

        const injector = await web3FromAddress(accountId32);
        extrinsic.signAndSend(
          accountId32,
          { signer: injector.signer },
          (status) => {
            try {
              if (subStateFun && typeof subStateFun == "function") {
                subStateFun(status);
              }
              console.log("status.status.toJSON()", status.status.toJSON());
              console.log("isFinalized", status.isFinalized);
              if (status.isFinalized) {
                const extrinsicHash = extrinsic.hash.toHex();
                resolve({ msg: "ok", data: extrinsicHash });
              }
            } catch (e) {
              console.log(e);
              reject(e.message);
            }
          },
          (e) => {
            console.log(e);
          },
        );
      } catch (e) {
        console.log(e);
        reject(e.message);
      }
    });
  }
  async getAccountsFromWallet() {
    let tmp=await web3Enable("cess");
    console.log('yes',tmp);
    const allAccounts = await web3Accounts();
    console.log('yes2');
    allAccounts.forEach((t) => {
      // t.setSS58Format(11330);
      t.address = this.formatAccountId(t.address);
    });
    return allAccounts;
  }

  async authSign(accountId32, msg) {
    await web3Enable("cess");
    const allAccounts = await web3Accounts();

    allAccounts.forEach((t) => {
      // t.setSS58Format(11330);
      t.address = this.formatAccountId(t.address);
    });
    let account = allAccounts.find((t) => t.address == accountId32);
    if (!account) {
      account = allAccounts[0];
      console.log("account not found!", allAccounts);
      // return { msg: "account not found!" };
      return {
        signU8A: null,
        signStr: null
      };
    }
    const injector = await web3FromSource(account.meta.source);
    const signRaw = injector?.signer?.signRaw;
    if (!signRaw) {
      return {
        signU8A: null,
        signStr: null
      };
    }
    // after making sure that signRaw is defined
    // we can use it to sign our message
    const { signature } = await signRaw({
      address: account.address,
      data: stringToHex(msg),
      type: "bytes",
    });
    // console.log({ signature });
    let signU8A = hexToU8a(signature);

    return {
      signU8A,
      signStr: signature
    };
  }

  formatAccountId(accountId32) {
    if (!accountId32 || accountId32.length == 64) {
      return accountId32;
    }
    const pair = this.keyring.addFromAddress(accountId32);
    return pair.address;
  }
};
